#ifndef _IMPOSTOR_H_
#define _IMPOSTOR_H_

#include "GLInstanceInfo.h"
#include "../algebra/Matrix.h"
#include "../geom/PolyModel.h"
#include "FBO.h"
#include "../geom/Point2D.h"
#include "shaderUtils.h"

namespace glutil
{
	/** Quad class used to draw impostors */
	class Quad
	{
		public:
			/** Default Constructor */
			Quad(){}
			/** Creates a quad through 4 points */
			Quad(const geom::Point3D &p1, const geom::Point3D &p2, const geom::Point3D &p3, const geom::Point3D &p4)
			{
				points[0] = p1, points[1] = p2, points[2] = p3, points[3] = p4;
			}
			/** Gets a point from the quad (read-only)*/
			const geom::Point3D & at(int index) const {return points[index];}
			/** Gets a point from the quad (read-write)*/
			geom::Point3D & at(int index) {return points[index];}
			/** Quad center*/
			geom::Point3D centerPoint;
			/** Quad corners */
			geom::Point3D points[4];
			/** Quad texture coordinates*/
			geom::Point2D uvs[4];
	};

	/** Impostor class, used to render complex models with few polygons. Needs a completely setup OpenGL context to be active.*/
	class Impostor
	{
		public:
			/** Creates an impostor from a model. 
				@param model Model to immitate
				@param maxTextureSide Maximum size the impostor texture can have on any given side
			 */
			Impostor(const geom::PolyModel & model, int maxTextureSide, float baseScale = 1.0f);
			/** Copy constructor */
			Impostor(const Impostor & other);
			/** Destructor */
			~Impostor();
			/** Adds another instance of this impostor to be rendered 
			  @param m Instance information
			 */
			void addInstance(const GLInstanceInfo &m);
			/** Removes all instances from the list*/
			void clearInstances(){ m_quads.clear();}
			/** Renders all impostors further from the camera than the specified distance 
			 @param camPos Camera position
			 @param startDistance Distance to start rendering
			 */
			void renderAllFartherThan(const geom::Point3D & camPos, float startDistance);

		private:
			Quad transformQuad(float * quadPoints, const algebra::Matrix4f & matrix) const;
			float xToZUV;
			float xToZUVPlusMargin;
			float zToWUV;
			float zToWUVPlusMargin;
			float vToUV;
			float m_baseScale;
			std::vector<Quad> m_quads;
			mutable ShaderProgram * m_shader;
			mutable GLuint m_image;
			util::Triplet<float> m_halfSides;
	};
}
#endif

